import Emoji from '@/components/Emoji';
import {
  commentLick,
  createComment,
  createCommentReply,
  findArticleCommentListByArticleId,
  findCommentReplyByComment,
} from '@/services/articles';
import { findUser } from '@/services/user';
import {
  DislikeFilled,
  DislikeOutlined,
  LikeFilled,
  LikeOutlined,
  SmileOutlined,
} from '@ant-design/icons';
import { useModel, useParams } from '@umijs/max';
import {
  Avatar,
  Button,
  Comment,
  Divider,
  Input,
  message,
  Pagination,
  Popover,
  Skeleton,
  Spin,
  Tooltip,
} from 'antd';
import type { ReactNode } from 'react';
import React, { createElement, useEffect, useMemo, useRef, useState } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';

import useRequest from '@ahooksjs/use-request';

import { showTimeText } from '@/utils';
import styles from './index.less';

type Props = {};

const { TextArea } = Input;

type PaginationT = {
  current: number;
  pageSize: number;
};
type ReplyListRender = {
  [x: string]: any;
  actions: ReactNode[];
  author: ReactNode | string;
  avatar: ReactNode | string;
  content: ReactNode | string;
  datetime: ReactNode | string;
};

interface CommentOrReplyT {
  commentId: number;
  commentReplyList?: COMMON.QueryListData<ARTICLEAPI.ReplyT>;
  nickname: string;
  headPortrait: string;
  commentReplyId?: number;
  replyUserId?: number;
  replyUserName?: string;
  commentContent?: string;
  content?: string | number;
  createTime: string;
  isShowReplyFrame?: boolean;
  isShowMore?: boolean;
  flagIsLick?: ARTICLEAPI.CommentStateT;
  likeState?: ARTICLEAPI.CommentStateT;
  likeCount: number;
  userId: number;
}
interface NewCommentT extends ARTICLEAPI.Comment {
  isShowReplyFrame: boolean;
  isShowMore: boolean;
  commentReplyList?: COMMON.QueryListData<ARTICLEAPI.ReplyT>;
  replyListRenders?: ReplyListRender[];
}

const Index: React.FC<Props> = () => {
  const { id: articleId = '' } = useParams<{ id: string }>();
  const commentBoxRef = useRef<HTMLDivElement>(null);
  const { initialState: { currentUser: { nickname = '', headPortrait = '' } = {} } = {} } =
    useModel('@@initialState');
  // 文章评论
  const [articleComments, setArticleComments] = useState<NewCommentT[]>([]);
  // 评论总数
  const [commentsTotal, setCommentsTotal] = useState<number>(0);
  // 回复目标详细信息
  const [replyTargetInfo, setReplyTargetInfo] = useState<USERAPI.UserInfo>();
  // 评论分页
  const [commentsPagination, setCommentsPaginationPagination] = useState<PaginationT>({
    current: 1,
    pageSize: 10,
  });
  // 是否显示浮动的评论框
  const [isIntersecting, setIsIntersecting] = useState<boolean>(false);
  // 选中的当前评论或者回复
  const [currentComment, setCurrentComment] = useState<CommentOrReplyT>();
  // 评论
  const [value, setValue] = useState<string>();
  // 回复
  const [replyValue, setReplyValue] = useState<string>();
  const [action, setAction] = useState<string | null>(null);
  const [likes, setLikes] = useState(0);
  const [dislikes, setDislikes] = useState(0);

  // 查询评论列表
  const { run: findArticleCommentRun, loading: findArticleCommentRunLoading } = useRequest(
    findArticleCommentListByArticleId,
    {
      onSuccess: (res) => {
        const { code, data: { records = [], total } = {} } = res;
        let newRecords = [];
        if (code === 200) {
          newRecords = records.map((item) => {
            return {
              isShowReplyFrame: false,
              isShowMore: false,
              ...item,
            };
          }) as NewCommentT[];
          setArticleComments(newRecords);
          setCommentsTotal(total || 0);
        }
      },
    },
  );
  // 查询评论回复
  const { run: findCommentReplyByCommentRun, loading: findCommentReplyByCommentLoading } =
    useRequest(findCommentReplyByComment, {
      manual: true,
      onSuccess: (res, params: (PaginationT & ARTICLEAPI.CommentReplyT)[]) => {
        const { code, data } = res;
        if (code === 200) {
          const newArticleComments = articleComments.map((item) => {
            const newItem = { ...item };
            if (item.commentId === params[0].commentId) {
              newItem.isShowMore = true;
              newItem.commentReplyList = data;
            }
            return newItem;
          });
          setArticleComments(newArticleComments);
        }
      },
    });
  // 获取回复目标信息
  const { run: findUserRun, loading: findUserLoading } = useRequest(findUser, {
    manual: true,
    onSuccess: (res) => {
      const { code, data, message: errorMessage } = res;
      if (code === 200) {
        setReplyTargetInfo(data);
      } else {
        message.error(errorMessage);
      }
    },
  });

  // 展开回复
  const changeIsShowMore = (id: number) => {
    findCommentReplyByCommentRun({
      current: 1,
      pageSize: 10,
      commentId: id,
    });
  };

  // 添加回复
  const addReplyHandler = async () => {
    if (replyValue && currentComment) {
      const { code } = await createCommentReply({
        replyUserId: currentComment.userId,
        // 如果有值就是二级回复
        replyUserName: currentComment.commentReplyId ? currentComment.nickname : undefined,
        commentId: currentComment.commentId,
        content: replyValue,
      });
      if (code === 200 && articleId) {
        changeIsShowMore(currentComment.commentId);
        setReplyValue('');
        message.success('回复成功!');
      }
    }
  };

  // 点赞 或者踩一下
  const like = async (param: CommentOrReplyT, likeState: 1 | 2) => {
    let neweState: ARTICLEAPI.CommentStateT = 0;
    if (!param.likeState) {
      neweState = likeState;
    }
    const { code, message: msg } = await commentLick({
      commentId: param.commentReplyId || param.commentId,
      state: neweState,
      likeType: param.commentReplyId ? 2 : 1,
    });
    if (code === 200) {
    } else {
      message.error(msg);
    }
  };

  /**
   * 回复框显示/隐藏
   * @param 当前行信息
   */
  const replyFrameHandler = (param: CommentOrReplyT) => {
    const newArticleComments = articleComments.map((item) => {
      const newItem = { ...item };
      if (item.commentId === param.commentId) {
        newItem.isShowReplyFrame = true;
      } else {
        newItem.isShowReplyFrame = false;
      }
      return newItem;
    });
    setArticleComments(newArticleComments);
    setCurrentComment({
      ...param,
      content: '',
    });
  };

  /**
   *
   * @param id 当前行信息
   * @returns
   */
  const actions = (param: CommentOrReplyT) => {
    const nodes = [
      <span key="comment-basic-reply-to" onClick={() => replyFrameHandler(param)}>
        回复
      </span>,
    ];
    if (param.likeState !== 1) {
      nodes.unshift(
        <Tooltip key="comment-basic-dislike" title="Dislike">
          <span onClick={() => like(param, 2)}>
            {createElement(!param.likeState ? DislikeOutlined : DislikeFilled, {
              style: { color: 'var(--ant-primary-color)' },
            })}
          </span>
        </Tooltip>,
      );
    }
    if (param.likeState !== 2) {
      nodes.unshift(
        <Tooltip key="comment-basic-like" title="Like">
          <span onClick={() => like(param, 1)}>
            {createElement(!param.likeState ? LikeOutlined : LikeFilled, {
              style: { color: 'var(--ant-primary-color)' },
            })}
            <span className="comment-action">{param.likeCount}</span>
          </span>
        </Tooltip>,
      );
    }
    return nodes;
  };

  const replyMoreHandler = (val: { commentId: number; isShowMore?: boolean; total: number }) => {
    if (!val.total || val.total <= 6) {
      return null;
    }
    return (
      <div className={styles.replyMore}>
        <Spin tip="Loading..." spinning={findCommentReplyByCommentLoading}>
          {!val.isShowMore ? (
            <div>
              共{val.total}条回复,
              <a onClick={() => changeIsShowMore(val.commentId)}>点击查看</a>
            </div>
          ) : (
            <div>
              <Pagination
                onChange={(current, pageSize) => {
                  findCommentReplyByCommentRun({
                    current,
                    pageSize,
                    commentId: val.commentId,
                  });
                }}
                hideOnSinglePage={true}
                showSizeChanger={false}
                defaultCurrent={1}
                total={val.total}
              />
            </div>
          )}
        </Spin>
      </div>
    );
  };
  // 追加评论
  const pushComeent = async (pagination: PaginationT) => {
    // 查询并拼接到评论后面
    const { code, data: { records = [], total } = {} } = await findArticleCommentListByArticleId({
      ...pagination,
      articleId,
    });
    let newRecords = [];
    if (code === 200) {
      newRecords = records.map((item) => {
        return {
          isShowReplyFrame: false,
          isShowMore: false,
          ...item,
        };
      }) as NewCommentT[];
      setArticleComments(articleComments.concat(newRecords));
      setCommentsTotal(total || 0);
    }
  };

  const replyUserInfoPopoverContent = () => {
    return (
      <div style={{ width: '300px' }}>
        <Spin spinning={findUserLoading}>
          <div className={styles.replyUserInfoWrapper}>
            <div className={styles.headSculpture}>
              <img src={replyTargetInfo?.headPortrait} alt="" />
            </div>
            <div className={styles.baseInfo}>
              <div className={styles.userName}>{replyTargetInfo?.nickname}</div>
              <div className={styles.attribute}>
                <div>16文章</div>
                <div>220获赞</div>
                <div>110收藏</div>
              </div>
            </div>
          </div>
        </Spin>
      </div>
    );
  };

  // 评论 || 回复列表Render
  const CommentOrReplyListRender = (val: CommentOrReplyT) => {
    let newcomments: ARTICLEAPI.ReplyT[] = [];
    if (val && val.commentReplyList && val.commentReplyList.records) {
      newcomments = val.commentReplyList.records;
    }
    const commentProps = {
      actions: actions({
        ...val,
        replyUserId: val.replyUserId || val.commentId,
        content: val.content || '',
      }),
      author: val.nickname,
      avatar: val.headPortrait,
      content: (
        <p>
          {val.replyUserName ? (
            <Popover
              showArrow={false}
              placement="topLeft"
              content={replyUserInfoPopoverContent}
              trigger="hover"
              onOpenChange={(visible: boolean) => {
                if (visible) {
                  findUserRun(val.userId);
                }
              }}
            >
              <a style={{ marginRight: '4px' }}>@{val.replyUserName}</a>
            </Popover>
          ) : null}
          {val.commentContent || val.content}
        </p>
      ),
      datetime: showTimeText(val.createTime),
    };
    return (
      <Comment {...commentProps} key={val.createTime}>
        {newcomments.map((item) => {
          return CommentOrReplyListRender(item);
        })}
        {val?.isShowReplyFrame ? (
          <div className={styles.footerReply}>
            <TextArea
              onChange={(e) => {
                setReplyValue(e.target.value);
              }}
              value={replyValue}
              placeholder={`回复${currentComment?.nickname}`}
              rows={2}
            />
            <div className={styles.editorFooter}>
              <Popover
                style={{ width: 900 }}
                content={
                  <Emoji
                    clickBack={(e: string) => {
                      let newValue = e;
                      if (replyValue) {
                        newValue = replyValue + e;
                      }
                      setReplyValue(newValue);
                    }}
                  />
                }
                trigger="hover"
              >
                <SmileOutlined style={{ fontSize: '22px', marginRight: '15px' }} />
              </Popover>
              <Button htmlType="submit" type="primary" onClick={() => addReplyHandler()}>
                添加回复
              </Button>
            </div>
          </div>
        ) : null}
        {val.commentReplyList?.records
          ? replyMoreHandler({ ...val, total: val.commentReplyList.total })
          : null}
      </Comment>
    );
  };

  const emojiSelectHandler = (e: string) => {
    let newValue = e;
    if (value) {
      newValue = value + e;
    }
    setValue(newValue);
  };

  // 添加评论
  const { run: createCommentRun, loading: createCommentLoading } = useRequest(createComment, {
    manual: true,
    onSuccess: (res) => {
      const { code } = res;
      if (code !== 200) message.error('评论失败!!!');
      pushComeent({ current: 1, pageSize: 1 });
      setValue('');
    },
  });

  const handleSubmit = () => {
    if (!value || !articleId) {
      return true;
    }
    createCommentRun({
      commentContent: value,
      articleId,
    });
  };

  const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    console.log(e.target.value);

    setValue(e.target.value);
  };

  // 加载更多
  const loadMoreData = () => {
    if (findArticleCommentRunLoading) {
      return;
    }
    setCommentsPaginationPagination({
      pageSize: 10,
      current: commentsPagination.current + 1,
    });
    pushComeent({ pageSize: 10, current: commentsPagination.current + 1 });
  };

  // 评论 || 回复列表
  const CommentList = useMemo(() => {
    return (
      <div className={styles.commentListWrapper}>
        <div className={styles.commentListHeader}>
          <h2>{articleComments.length}条评论</h2>
        </div>
        <div className={styles.commentItemWrapper}>
          <InfiniteScroll
            dataLength={articleComments.length}
            next={loadMoreData}
            hasMore={articleComments.length < commentsTotal}
            loader={<Skeleton avatar paragraph={{ rows: 1 }} active />}
            endMessage={<Divider plain />}
            scrollableTarget="scrollableDiv"
          >
            {articleComments.map((item) => (
              <div key={item.commentId}>{CommentOrReplyListRender(item)}</div>
            ))}
          </InfiniteScroll>
        </div>
        <div
          className={styles.commentFooter}
          style={{ opacity: isIntersecting ? '0' : '1', zIndex: isIntersecting ? -1 : 99 }}
        >
          <TextArea placeholder="友善发言" rows={2} onChange={handleChange} value={value} />
          <div className={styles.editorFooter}>
            <Popover
              style={{ width: 900 }}
              content={<Emoji clickBack={(val) => emojiSelectHandler(val)} />}
              trigger="hover"
            >
              <SmileOutlined style={{ fontSize: '22px', marginRight: '15px' }} />
            </Popover>
            <Button
              htmlType="submit"
              loading={createCommentLoading}
              onClick={handleSubmit}
              type="primary"
            >
              添加评论
            </Button>
          </div>
        </div>
      </div>
    );
  }, [articleComments, commentsTotal, isIntersecting, value, createCommentLoading, replyValue]);

  useEffect(() => {
    findArticleCommentRun({
      ...commentsPagination,
      articleId,
    });
    if (commentBoxRef.current) {
      const observer = new IntersectionObserver(
        ([change]) => {
          setIsIntersecting(change.isIntersecting);
        },
        {
          threshold: [1.0],
          /**
           * 这里设置5000px 是为了防止在评论上面出现这个浮动评论 所以把下边界(下边距)检测放无限大
           * 也就是监听的元素永远不会在下边界消失
           */
          rootMargin: `0px 0px 5000px 0px`,
        },
      );
      if (observer) {
        observer.observe(commentBoxRef.current);
      }
      return () => {
        // 关闭监听
        if (observer) {
          observer.disconnect();
        }
      };
    }
  }, [articleId]);
  return (
    <div>
      <div className={styles.commentArea}>
        <Avatar src={headPortrait} alt={nickname} />
        <div ref={commentBoxRef}>
          <TextArea placeholder="友善发言" rows={4} onChange={handleChange} value={value} />
          <div className={styles.editorFooter}>
            <Popover
              style={{ width: 900 }}
              content={<Emoji clickBack={(val) => emojiSelectHandler(val)} />}
              trigger="hover"
            >
              <SmileOutlined style={{ fontSize: '22px', marginRight: '15px' }} />
            </Popover>
            <Button
              htmlType="submit"
              loading={createCommentLoading}
              onClick={handleSubmit}
              type="primary"
            >
              添加评论
            </Button>
          </div>
        </div>
      </div>
      {articleComments.length > 0 && CommentList}
    </div>
  );
};
export default Index;
